//
//  LinkMapParser.swift
//  JKTool
//
//  Created by liuyan on 2023/5/26.
//

import Foundation

struct LinkMapParser {
    func parseContent(path: String) -> [String: UInt]? {
        guard FileManager.default.fileExists(atPath: path) else {
            po(tip: "请选择正确的Link Map文件路径", type: .error)
            return nil
        }
        
        guard let content = try? String(contentsOfFile: path, encoding: .macOSRoman), checkContent(content) else {
            po(tip: "Link Map文件格式有误", type: .error)
            return nil
        }
        
        let symbolMap = symbolMapFromContent(content)
        var sizeMap = [String: UInt]()
        for symbol in symbolMap.values {
            if let name = symbol.file.components(separatedBy: "/").last {
                sizeMap[name] = symbol.size
            }
        }
        return sizeMap
    }
    
    func checkContent(_ content: String) -> Bool {
        return content.contains("# Path:") && content.contains("# Object files:") && content.contains("# Sections:") && content.contains("Symbols:")
    }
    
    func symbolMapFromContent(_ content: String) -> Dictionary<String, SymbolModel> {
        var symbolMap = [String: SymbolModel]()
        let lines = content.components(separatedBy: "\n")
        
        var reachFiles = false
        var reachSections = false
        var reachSymbols = false
        
        for line in lines {
            if line.hasPrefix("#") {
                if line.hasPrefix("# Object files:") {
                    reachFiles = true
                } else if line.hasPrefix("# Sections:") {
                    reachSections = true
                } else if line.hasPrefix("# Symbols:") {
                    reachSymbols = true
                }
            } else if reachFiles == true && reachSections == false && reachSymbols == false {
                if let range = line.range(of: "]") {
                    let file = line[line.index(after: range.upperBound)...]
                    let key = line[line.startIndex...range.upperBound]
                    symbolMap[String(key)] = SymbolModel(file: String(file), size: 0)
                }
            } else if reachFiles == true && reachSections == true && reachSymbols == true {
                let symbolsArray = line.components(separatedBy: "\t")
                if symbolsArray.count == 3 {
                    let fileKeyAndName = symbolsArray[2]
                    let size = strtoul(symbolsArray[1].cString(using: .utf8), nil, 16)
                    if let range = fileKeyAndName.range(of: "]") {
                        let key = fileKeyAndName[fileKeyAndName.startIndex...range.upperBound]
                        if var symbol = symbolMap[String(key)] {
                            symbol.size = symbol.size + size
                            symbolMap[String(key)] = symbol
                        }
                    }
                }
            }
        }
        return symbolMap
    }
}

struct SymbolModel {
    var file: String
    var size: UInt
}


